/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package kuti.grp5.ui;

import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import kuti.*;
import kuti.grp5.Factory;

/**
 * This class is designed to give its user a list of WorldElements created randomly
 * across the map.
 * @author Jocelyn
 */
public abstract class RandomWorldGenerator {
    
    // Random object used in various object creations
    private static Random r = new Random();
    
    /**
     * Creates random elements according to maximums given in parameters
     * Each type of object is created between 0 and ***max times (both inclusive)
     * or ***max times according to the randomCount boolean value.
     * @param nbKutisMax - Max number of Kutis.
     * @param nbStationsMax - Max number of charging stations.
     * @param nbObstMax  - Max number of obstacles.
     * @param nbObstMagnMax - Max number of magnetic obstacles.
     * @param isp - SimulParams necessary to know several variables
     * @param randomCount - If true, each object is created between 0 and ***max times (both inclusive).
     *                      If false, each object is created ***max times.
     * @return The List<IWorldElement> of the random elements.
     */
    public static List<IWorldElement> generateRandomWorld(int nbKutisMax, int nbStationsMax, int nbObstMax, int nbObstMagnMax,
            ISimulParams isp, boolean randomCount) {
        List<IWorldElement> elts = new ArrayList<IWorldElement>();
        
        int nbKutis = randomCount ? r.nextInt(nbKutisMax+1) : nbKutisMax;
        int nbStations = randomCount ? r.nextInt(nbStationsMax+1) : nbStationsMax;
        int nbObst = randomCount ? r.nextInt(nbObstMax+1) : nbObstMax;
        int nbObstMagn = randomCount ? r.nextInt(nbObstMagnMax+1) : nbObstMagnMax;
        
        generateRandomChargingStations(nbStations, isp, elts);
        generateRandomObst(nbObst, false, isp, elts);
        generateRandomObst(nbObstMagn, true, isp, elts);
        generateRandomKutis(nbKutis, isp, elts);
        
        return elts;
    }
    
    /**
     * Generates the amount of Kutis given in parameters and puts it in the List.
     * @param nbKutis - Amount of Kuti to create
     * @param isp - SimParams to know the diameter of a Kuti
     * @param elts  - List to put Kutis in.
     */
    private static void generateRandomKutis(int nbKutis, ISimulParams isp, List<IWorldElement> elts) {
        Factory f = new Factory(isp);
        Point2D center;
        int x, y;
        double angle;
        
        for (int i = 0; i < nbKutis; i++) {
            do {
                x = r.nextInt(ISimulParams.WORLD_WIDTH - (int) isp.getKDiameter()) + (int) isp.getKDiameter() / 2;
                y = r.nextInt(ISimulParams.WORLD_HEIGHT - (int) isp.getKDiameter()) + (int) isp.getKDiameter() / 2;
                angle = r.nextDouble() * Math.PI * 2;
                
                center = new Point2D.Double(x, y);
            } while (!CollisionChecker.isKutiPlacementValid(center, elts, isp.getKDiameter()));
            elts.add(f.newKuti(center, angle, f.newDriver()));
        }
    }
    
    /**
     * Generates the amount of Charging stations given in parameters and puts it in the List.
     * @param nbStations - Amount of Charging Station to create
     * @param isp - SimParams to know the diameter of a Kuti
     * @param elts  - List to put charging stations in
     */
    private static void generateRandomChargingStations(int nbStations, ISimulParams isp, List<IWorldElement> elts) {
        Factory f = new Factory(isp);
        int x, y;
        double tau, width, height, radius;
        Point2D center;
        
        for (int i = 0; i < nbStations; i++) {
            do {
                x = r.nextInt(ISimulParams.WORLD_WIDTH - (int) isp.getKDiameter()) + (int) isp.getKDiameter() / 2;
                y = r.nextInt(ISimulParams.WORLD_HEIGHT - (int) isp.getKDiameter()) + (int) isp.getKDiameter() / 2;
                height = isp.getKDiameter()*2;
                width = isp.getKDiameter()*2;
                radius = Math.sqrt(height*height + width*width) / 2;
                center = new Point2D.Double(x, y);
                tau = (r.nextDouble()*isp.getKMaxEnergy())%100;
            } while (!CollisionChecker.isStationPlacementValid(center, radius, width, height, elts, isp.getKDiameter()));
            elts.add(f.newChargingStation(center, height, width, tau));
        }
    }
    
    /**
     * Generates the amount of Obstacles (magnetic or not) given in parameters and puts it in the List.
     * @param nbObst - Amount of obstacles to create
     * @param magn - true if magnetic
     * @param isp - SimulParams to know diameter of Kuti
     * @param elts - List to put obstacles in
     */
    private static void generateRandomObst(int nbObst, boolean magn, ISimulParams isp, List<IWorldElement> elts) {
        Factory f = new Factory(isp);
        Line2D segment;
        int startX, startY, endX, endY;
        
        
        for (int i = 0; i < nbObst; i++) {
            do{
            startX = r.nextInt(ISimulParams.WORLD_WIDTH);
            startY = r.nextInt(ISimulParams.WORLD_HEIGHT);
            endX = r.nextInt(ISimulParams.WORLD_WIDTH);
            endY = r.nextInt(ISimulParams.WORLD_HEIGHT);
            
            segment = new Line2D.Double(startX, startY, endX, endY);
            }while(!CollisionChecker.isObstaclePlacementValid(segment, elts, isp.getKDiameter()));
            IObstacle obstacle = f.newObstacle(segment);
            if (magn) {
                obstacle = f.newMagneticObstacle(obstacle);
            }
            elts.add(obstacle);
        }
    }
}
